/*
 * IMP Decoder func header file.
 *
 * Copyright (C) 2015 Ingenic Semiconductor Co.,Ltd
 */

#include <string.h>
#include <semaphore.h>
#include <stdlib.h>
#include <sys/prctl.h>
#include <unistd.h>

#include <constraints.h>
#include <system/group.h>
#include <system/device.h>
#include <imp/imp_log.h>
#include <imp/imp_common.h>
#include <imp/imp_utils.h>
#include <imp/imp_decoder.h>
#include "imp_video_common.h"
#include <system/system.h>

#include <ijpegd.h>
#ifdef DMALLOC
#include <imp/dmalloc.h>
#endif
#define TAG "Decoder"
#define PROCESSTIMEOUTUS			100000

typedef struct {
	ijpegd_param_t	ijpegd_param;
	ijpegd_t		*ijpegdHandler;
} IjpegdData;

typedef struct {
	ijpegd_pic_t pic_out;
	ijpegd_nal_t nal_in;
} IjpegdElem;

typedef struct {
	imp_video_list_t	list;
	IMPFrameInfo		frameInfo;
	IMPDecoderStream	decStream;
	union {
		IjpegdElem		ijpegelem;
	} decElem;
} StreamHandler;

typedef struct {
	pthread_mutex_t		handlerMutex;
	sem_t				freeHandlerSem;
	sem_t				busyHandlerSem;
	sem_t				doneHandlerSem;
	sem_t				tickSem;
	imp_video_list_t	freeStreamHandler;
	imp_video_list_t	busyStreamHandler;
	imp_video_list_t	doneStreamHandler;
	StreamHandler		*streamHandler;
	pthread_t			workThread;
	pthread_t			tickThread;
	struct timespec		timeSpec;
} StreamContainer;

typedef struct {
	int					index;
	int					recvPic;
	IMPDecoderCHNAttr	attr;
	IjpegdData			ijpegd;
	StreamContainer		container;
} DecChannel;

typedef struct {
	int			index;
	int			nr_dec_chn;
	DecChannel *channel[NR_MAX_DEC_CHN_IN_GROUP];
} DecGroup;

typedef struct {
	Device		*device;
	DecGroup	decGroup[NR_MAX_DEC_GROUPS];
} Decoder;

static DecChannel g_DecChannel[NR_MAX_DEC_CHN];
static Decoder	*gDecoder = NULL;

/* push handler to end */
static void push_handler(DecChannel *dec_chn, imp_video_list_t *head, imp_video_list_t *new)
{
	pthread_mutex_lock(&dec_chn->container.handlerMutex);
	new->next = head;
	new->prev = head->prev;
	head->prev->next = new;
	head->prev = new;
	pthread_mutex_unlock(&dec_chn->container.handlerMutex);
}

/* push handler from head */
static void pop_handler(DecChannel *dec_chn, imp_video_list_t *head, imp_video_list_t **new)
{
	pthread_mutex_lock(&dec_chn->container.handlerMutex);
	if (head->next == head) {
		*new = NULL;
	} else {
		*new = head->next;
		head->next = head->next->next;
		head->next->prev = head;
		(*new)->next = (*new)->prev = *new;
	}
	pthread_mutex_unlock(&dec_chn->container.handlerMutex);
}

static int decoder_init(Decoder *decoder)
{
	/* Decoder initial work here. */

	return 0;
}

static void decoder_exit(Decoder *decoder)
{
	/* Exit work here. */
}

static Decoder *alloc_decoder(void)
{
	Decoder *decoder = NULL;
	Device *dev = alloc_device("Decoder", sizeof(Decoder));
	if (dev == NULL) {
		IMP_LOG_ERR(TAG, "alloc_device() error\n");
		goto err_alloc_device;
	}
	dev->nr_groups = NR_MAX_DEC_GROUPS;
	dev->dev_id = DEV_ID_DEC;

	decoder = device_pri(dev);
	decoder->device = dev;

	return decoder;

err_alloc_device:
	return NULL;
}

static void free_decoder(Decoder *decoder)
{
	if (decoder && decoder->device) {
		Device *dev = decoder->device;
		free_device(dev);
	}
}

int DecoderInit(void)
{
	int i;

	gDecoder = alloc_decoder();
	if (gDecoder == NULL) {
		IMP_LOG_ERR(TAG, "alloc gDecoder failed\n");
		goto err_alloc_decoder;
	}

	if (decoder_init(gDecoder) < 0) {
		IMP_LOG_ERR(TAG, "decoder_init failed\n");
		goto err_decoder_init;
	}

	/* g_DecChannel create instance */
	memset(g_DecChannel, 0, NR_MAX_DEC_CHN * sizeof(DecChannel));
	for (i = 0; i < NR_MAX_DEC_CHN; i++) {
		g_DecChannel[i].index = -1;	/* It's a uninitial state */
	}

	return 0;

err_decoder_init:
	free_decoder(gDecoder);
	gDecoder = NULL;
err_alloc_decoder:
	return -1;
}

int DecoderExit(void)
{
	if (gDecoder) {
		decoder_exit(gDecoder);
		free_decoder(gDecoder);
		gDecoder = NULL;
	}

	return 0;
}

static int pixel_format_to_csp(IMPPixelFormat pixel_format)
{
	switch(pixel_format) {
		case PIX_FMT_YUV420P:
			return C_CSP_I420;
		case PIX_FMT_NV12:
			return C_CSP_NV12;
		case PIX_FMT_NV21:
			return C_CSP_NV21;
		default:
			IMP_LOG_ERR(TAG, "unsupported required format\n");
			return -1;
	}

	return C_CSP_NV12;
}

static int channel_ijpegd_decoder_init(DecChannel *dec_chn)
{
	ijpegd_param_default(&dec_chn->ijpegd.ijpegd_param);
	if (IS_SOC_SERIES(T10)) {
		dec_chn->ijpegd.ijpegd_param.soc = C_T10;
	} else if (IS_SOC_SERIES(T20)) {
		dec_chn->ijpegd.ijpegd_param.soc = C_T20;
	} else if (IS_SOC_SERIES(T30)){
		dec_chn->ijpegd.ijpegd_param.soc = C_T30;
	}else if (IS_SOC_SERIES(T21)){
		dec_chn->ijpegd.ijpegd_param.soc = C_T21;
	}else if (IS_SOC_SERIES(T23)){
		dec_chn->ijpegd.ijpegd_param.soc = C_T23;
	} else {
		IMP_LOG_ERR(TAG, "soc type (%d) not support yet\n", get_cpu_id());
		return -1;
	}
	dec_chn->ijpegd.ijpegd_param.b_tlb = 0;
	dec_chn->ijpegd.ijpegd_param.b_use_phy = 1;
	dec_chn->ijpegd.ijpegd_param.i_csp = pixel_format_to_csp(dec_chn->attr.decAttr.pixelFormat);
	if (dec_chn->ijpegd.ijpegd_param.i_csp < 0) {
		IMP_LOG_ERR(TAG, "Unsupport pixelFormat %d\n", dec_chn->attr.decAttr.pixelFormat);
		goto err_inv_pixel_format;
	}
	dec_chn->ijpegd.ijpegd_param.i_max_width = dec_chn->attr.decAttr.maxWidth;
	dec_chn->ijpegd.ijpegd_param.i_max_height = dec_chn->attr.decAttr.maxHeight;

	dec_chn->ijpegd.ijpegd_param.ckmalloc = video_vbm_malloc;
	dec_chn->ijpegd.ijpegd_param.ckfree = video_vbm_free;
	dec_chn->ijpegd.ijpegd_param.ckvirt_to_phys = video_vbm_virt_to_phys;
	dec_chn->ijpegd.ijpegd_param.ckphys_to_virt = video_vbm_phys_to_virt;
	dec_chn->ijpegd.ijpegdHandler = ijpegd_init(&dec_chn->ijpegd.ijpegd_param);
	if (dec_chn->ijpegd.ijpegdHandler == NULL) {
		IMP_LOG_ERR(TAG, "ijpegd_init failed\n");
		goto err_ijpegd_init;
	}
	return 0;

err_ijpegd_init:
err_inv_pixel_format:
	return -1;
}

static int channel_ijpegd_decoder_exit(DecChannel *dec_chn)
{
	if (dec_chn->ijpegd.ijpegdHandler) {
		ijpegd_deinit(dec_chn->ijpegd.ijpegdHandler);
	}

	return 0;
}

static int channel_decoder_init(DecChannel *dec_chn)
{
	switch (dec_chn->attr.decAttr.decType) {
		case PT_JPEG:
			return channel_ijpegd_decoder_init(dec_chn);
		default:
			IMP_LOG_ERR(TAG, "Unsupport decoder protocol %d\n", dec_chn->attr.decAttr.decType);
			return -1;
	}
	return 0;
}

static int channel_decoder_exit(DecChannel *dec_chn)
{
	switch (dec_chn->attr.decAttr.decType) {
		case PT_JPEG:
			return channel_ijpegd_decoder_exit(dec_chn);
		default:
			IMP_LOG_ERR(TAG, "Unsupport decoder protocol %d\n", dec_chn->attr.decAttr.decType);
			return -1;
	}
	return 0;
}

int channel_do_decode_jpeg_process(DecChannel *dec_chn)
{
	StreamHandler *streamHandler = NULL;
	imp_video_list_t *list = NULL;
	IjpegdElem *ijpegdElem = NULL;
	int dbusy_val = 0;
	while (1) {
jpeg_process_retry_point:
		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
		sem_getvalue(&dec_chn->container.busyHandlerSem, &dbusy_val);
#if 0
		int dfree_val = 0, ddone_val = 0;
		sem_getvalue(&dec_chn->container.freeHandlerSem, &dfree_val);
		sem_getvalue(&dec_chn->container.doneHandlerSem, &ddone_val);
		IMP_LOG_DBG(TAG, "%s(%d): dbusy_val=%d, dfree_val=%d, done_val=%d\n", __func__, __LINE__, dbusy_val, dfree_val, ddone_val);
#endif
	if (dbusy_val) {
			sem_trywait(&dec_chn->container.tickSem);
		} else {
			sem_wait(&dec_chn->container.tickSem);
		}
		if (video_sem_timedwait(&dec_chn->container.busyHandlerSem, &dec_chn->container.timeSpec) < 0) {
			IMP_LOG_WARN(TAG, "video_sem_timedwait busyHandlerSem failed\n");
			goto jpeg_process_retry_point;
		}
		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
		pop_handler(dec_chn, &dec_chn->container.busyStreamHandler, &list);
		if (list == NULL) {
			IMP_LOG_WARN(TAG, "busyStreamHandler should have member but empty\n");
			goto err_pop_busyStreamHandler;
		}
		streamHandler = container_of(list, StreamHandler, list);
		ijpegdElem = &streamHandler->decElem.ijpegelem;
		ijpegd_decode(dec_chn->ijpegd.ijpegdHandler, &ijpegdElem->pic_out, &ijpegdElem->nal_in);
		push_handler(dec_chn, &dec_chn->container.doneStreamHandler, list);
		sem_post(&dec_chn->container.doneHandlerSem);
	}
	return 0;

err_pop_busyStreamHandler:
	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
	return -1;
}

static void *channel_do_decode_process(void *arg)
{
	DecChannel *dec_chn = (DecChannel *)arg;
	char thread_name[64];

	sprintf(thread_name, "DEC(%d)-%s", dec_chn->index, __func__);
	prctl(PR_SET_NAME, (unsigned long)thread_name);

	switch (dec_chn->attr.decAttr.decType) {
		case PT_JPEG:
			return (void *)channel_do_decode_jpeg_process(dec_chn);
		default:
			IMP_LOG_ERR(TAG, "Unsupport decoder protocol %d\n", dec_chn->attr.decAttr.decType);
			return (void *)-1;
	}
	return (void *)0;
}

static void *channel_do_decode_tick_process(void *arg)
{
	DecChannel *dec_chn = (DecChannel *)arg;
	while (1) {
		if (dec_chn->recvPic) {
			sem_post(&dec_chn->container.tickSem);
		}
		usleep(1000000 * dec_chn->attr.decAttr.frmRateDen / dec_chn->attr.decAttr.frmRateNum);
	}
	return NULL;
}

int channel_decoder_thread_init(DecChannel *dec_chn)
{
	int i = 0, errnum = 0;
	int framesize = C_ALIGN(dec_chn->attr.decAttr.maxWidth, 16) * C_ALIGN(dec_chn->attr.decAttr.maxHeight, 16) * 3 / 2;

	dec_chn->container.streamHandler = calloc(dec_chn->attr.decAttr.nrKeepStream, sizeof(StreamHandler));
	if (dec_chn->container.streamHandler == NULL) {
		IMP_LOG_ERR(TAG, "calloc dec_chn->container.streamHandler failed\n");
		goto err_calloc_streamHandler;
	}

	for (i = 0; i < dec_chn->attr.decAttr.nrKeepStream; i++) {
		IMPFrameInfo *frameInfo = &dec_chn->container.streamHandler[i].frameInfo;
		IMPDecoderNal *decoderNal = &dec_chn->container.streamHandler[i].decStream.decoderNal;
		frameInfo->virAddr = (uint32_t)video_vbm_malloc(-1, framesize, 4096);
		if (frameInfo->virAddr == 0) {
			IMP_LOG_ERR(TAG, "video_vbm_malloc(%d) failed\n", framesize);
			goto err_video_vbm_malloc;
		}
		frameInfo->phyAddr = video_vbm_virt_to_phys(frameInfo->virAddr);
		frameInfo->width = C_ALIGN(dec_chn->attr.decAttr.maxWidth, 16);
		frameInfo->height = C_ALIGN(dec_chn->attr.decAttr.maxHeight, 16);
		frameInfo->pixfmt = dec_chn->attr.decAttr.pixelFormat;
		frameInfo->size = framesize;

		decoderNal->p_payload = malloc(framesize);
		if (decoderNal->p_payload == NULL) {
			IMP_LOG_ERR(TAG, "malloc decoderNal->p_payload failed\n", framesize);
			video_vbm_free(-1 ,(void *)frameInfo->virAddr);
			goto err_decoderNal_p_payload_malloc;
		}
	}

	errnum = pthread_mutex_init(&dec_chn->container.handlerMutex, NULL);
	if (errnum) {
		IMP_LOG_ERR(TAG, "pthread_mutex_init handlerMutex failed:%s\n", strerror(errnum));
		goto err_pthread_mutex_init_handlerMutex;
	}

	if (sem_init(&dec_chn->container.freeHandlerSem, 0, dec_chn->attr.decAttr.nrKeepStream) < 0) {
		IMP_LOG_ERR(TAG, "sem_init freeHandlerSem failed\n");
		goto err_sem_init_freeHandlerSem;
	}

	if (sem_init(&dec_chn->container.busyHandlerSem, 0, 0) < 0) {
		IMP_LOG_ERR(TAG, "sem_init busyHandlerSem failed\n");
		goto err_sem_init_busyHandlerSem;
	}

	if (sem_init(&dec_chn->container.doneHandlerSem, 0, 0) < 0) {
		IMP_LOG_ERR(TAG, "sem_init doneHandlerSem failed\n");
		goto err_sem_init_doneHandlerSem;
	}

	if (sem_init(&dec_chn->container.tickSem, 0, 0) < 0) {
		IMP_LOG_ERR(TAG, "sem_init tickSem failed\n");
		goto err_sem_init_tickSem;
	}

	dec_chn->container.freeStreamHandler.prev = dec_chn->container.freeStreamHandler.next = &dec_chn->container.freeStreamHandler;
	dec_chn->container.busyStreamHandler.prev = dec_chn->container.busyStreamHandler.next = &dec_chn->container.busyStreamHandler;
	dec_chn->container.doneStreamHandler.prev = dec_chn->container.doneStreamHandler.next = &dec_chn->container.doneStreamHandler;

	for (i = 0; i < dec_chn->attr.decAttr.nrKeepStream; i++) {
		push_handler(dec_chn, &dec_chn->container.freeStreamHandler, &dec_chn->container.streamHandler[i].list);
	}

	dec_chn->container.timeSpec.tv_sec = PROCESSTIMEOUTUS / 1000000;
	dec_chn->container.timeSpec.tv_nsec = (PROCESSTIMEOUTUS % 1000000) * 1000;

	if (pthread_create(&dec_chn->container.workThread, NULL, channel_do_decode_process, dec_chn) < 0) {
		IMP_LOG_ERR(TAG, "pthread_create workThread failed\n");
		goto err_pthread_create_workThread;
	}

	if (pthread_create(&dec_chn->container.tickThread, NULL, channel_do_decode_tick_process, dec_chn) < 0) {
		IMP_LOG_ERR(TAG, "pthread_create workThread failed\n");
		goto err_pthread_create_tickThread;
	}

	return 0;

err_pthread_create_tickThread:
	pthread_cancel(dec_chn->container.workThread);
	pthread_join(dec_chn->container.workThread, NULL);
err_pthread_create_workThread:
	sem_destroy(&dec_chn->container.tickSem);
err_sem_init_tickSem:
	sem_destroy(&dec_chn->container.doneHandlerSem);
err_sem_init_doneHandlerSem:
	sem_destroy(&dec_chn->container.busyHandlerSem);
err_sem_init_busyHandlerSem:
	sem_destroy(&dec_chn->container.freeHandlerSem);
err_sem_init_freeHandlerSem:
	pthread_mutex_destroy(&dec_chn->container.handlerMutex);
err_pthread_mutex_init_handlerMutex:
	i = dec_chn->attr.decAttr.nrKeepStream;
err_decoderNal_p_payload_malloc:
err_video_vbm_malloc:
	for (--i; i >= 0; i--) {
		video_vbm_free(-1, (void *)dec_chn->container.streamHandler[i].frameInfo.virAddr);
		free(dec_chn->container.streamHandler[i].decStream.decoderNal.p_payload);
	}
	free(dec_chn->container.streamHandler);
	dec_chn->container.streamHandler = NULL;
err_calloc_streamHandler:
	return -1;
}

int channel_decoder_thread_exit(DecChannel *dec_chn)
{
	int i = 0;

	pthread_cancel(dec_chn->container.tickThread);
	pthread_join(dec_chn->container.tickThread, NULL);
	pthread_cancel(dec_chn->container.workThread);
	pthread_join(dec_chn->container.workThread, NULL);
	dec_chn->container.freeStreamHandler.prev = dec_chn->container.freeStreamHandler.next = &dec_chn->container.freeStreamHandler;
	dec_chn->container.busyStreamHandler.prev = dec_chn->container.busyStreamHandler.next = &dec_chn->container.busyStreamHandler;
	sem_destroy(&dec_chn->container.tickSem);
	sem_destroy(&dec_chn->container.busyHandlerSem);
	sem_destroy(&dec_chn->container.freeHandlerSem);
	pthread_mutex_destroy(&dec_chn->container.handlerMutex);
	for (i = dec_chn->attr.decAttr.nrKeepStream - 1; i >= 0; i--) {
		video_vbm_free(-1, (void *)dec_chn->container.streamHandler[i].frameInfo.virAddr);
		free(dec_chn->container.streamHandler[i].decStream.decoderNal.p_payload);
	}
	free(dec_chn->container.streamHandler);
	dec_chn->container.streamHandler = NULL;

	return 0;
}

int IMP_Decoder_CreateChn(int decChn, const IMPDecoderCHNAttr *attr)
{
	DecChannel *dec_chn = NULL;

	if ((decChn < 0) || (decChn >= NR_MAX_DEC_CHN)) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", decChn);
		goto err_channel_num;
	}

	if (attr == NULL) {
		IMP_LOG_ERR(TAG, "Invalid attr, channel Num: %d\n", decChn);
		goto err_inv_attr;
	}

	dec_chn = &g_DecChannel[decChn];
	if (dec_chn->index >= 0) {
		IMP_LOG_ERR(TAG, "the Decoder Channel id=%d has been created\n", decChn);
		goto err_inv_decChn;
	}

	memset(dec_chn, 0, sizeof(DecChannel));
	memcpy(&dec_chn->attr, attr, sizeof(IMPDecoderCHNAttr));

	if (channel_decoder_init(dec_chn) < 0) {
		IMP_LOG_ERR(TAG, "channel_decoder_init decChn=%d failed\n", decChn);
		goto err_channel_decoder_init;
	}

	if (channel_decoder_thread_init(dec_chn) < 0) {
		IMP_LOG_ERR(TAG, "channel_decoder_thread_init decChn=%d failed\n", decChn);
		goto err_channel_decoder_thread_init;
	}

	pthread_mutex_lock(&dec_chn->container.handlerMutex);
	dec_chn->index = decChn;
	pthread_mutex_unlock(&dec_chn->container.handlerMutex);

	return 0;

err_channel_decoder_thread_init:
	channel_decoder_exit(dec_chn);
err_channel_decoder_init:
err_inv_decChn:
err_inv_attr:
err_channel_num:
	return -1;
}

int IMP_Decoder_DestroyChn(int decChn)
{
	DecChannel *dec_chn = NULL;

	if ((decChn < 0) || (decChn >= NR_MAX_DEC_CHN)) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", decChn);
		goto err_channel_num;
	}

	dec_chn = &g_DecChannel[decChn];

	if (dec_chn->index < 0) {
		IMP_LOG_ERR(TAG, "the Decoder Channel id=%d hasn't been created\n", decChn);
		goto err_inv_decChn;
	}

	channel_decoder_thread_exit(dec_chn);
	channel_decoder_exit(dec_chn);

	pthread_mutex_lock(&dec_chn->container.handlerMutex);
	dec_chn->index = -1;
	pthread_mutex_unlock(&dec_chn->container.handlerMutex);

	return 0;

err_inv_decChn:
err_channel_num:
	return -1;
}

int IMP_Decoder_StartRecvPic(int decChn)
{
	DecChannel *dec_chn = NULL;

	if ((decChn < 0) || (decChn >= NR_MAX_DEC_CHN)) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", decChn);
		goto err_channel_num;
	}

	dec_chn = &g_DecChannel[decChn];
	if (dec_chn->index < 0) {
		IMP_LOG_ERR(TAG, "the Decoder Channel id=%d hasn't been created\n", decChn);
		goto err_inv_decChn;
	}

	pthread_mutex_lock(&dec_chn->container.handlerMutex);
	dec_chn->recvPic = 1;
	pthread_mutex_unlock(&dec_chn->container.handlerMutex);

	return 0;

err_inv_decChn:
err_channel_num:
	return -1;
}

int IMP_Decoder_StopRecvPic(int decChn)
{
	DecChannel *dec_chn = NULL;

	if ((decChn < 0) || (decChn >= NR_MAX_DEC_CHN)) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", decChn);
		goto err_channel_num;
	}

	dec_chn = &g_DecChannel[decChn];

	if (dec_chn->index < 0) {
		IMP_LOG_ERR(TAG, "the Decoder Channel id=%d hasn't been created\n", decChn);
		goto err_inv_decChn;
	}

	pthread_mutex_lock(&dec_chn->container.handlerMutex);
	dec_chn->recvPic = 0;
	pthread_mutex_unlock(&dec_chn->container.handlerMutex);

	return 0;

err_inv_decChn:
err_channel_num:
	return -1;
}

int IMP_Decoder_SendStreamTimeout(int decChn, IMPDecoderStream *stream, uint32_t timeoutMsec)
{
	DecChannel *dec_chn = NULL;
	struct timespec timeSpec = {
		.tv_sec = timeoutMsec / 1000,
		.tv_nsec = (timeoutMsec % 1000) * 1000000,
	};
	imp_video_list_t *list = NULL;
	StreamHandler *streamHandler = NULL;
	ijpegd_pic_t *ppic_out = NULL;
	ijpegd_nal_t *pnal_in = NULL;
	int framesize = 0;

	if ((decChn < 0) || (decChn >= NR_MAX_DEC_CHN)) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", decChn);
		goto err_channel_num;
	}

	dec_chn = &g_DecChannel[decChn];
	if (dec_chn->index < 0) {
		IMP_LOG_ERR(TAG, "the Decoder Channel id=%d hasn't been created\n", decChn);
		goto err_inv_decChn;
	}

	if (video_sem_timedwait(&dec_chn->container.freeHandlerSem, &timeSpec) < 0) {
		IMP_LOG_ERR(TAG, "Channel Num:%d video_sem_timedwait freeHandlerSem failed\n", decChn);
		goto err_video_sem_timedwait_freeHandlerSem;
	}

	pop_handler(dec_chn, &dec_chn->container.freeStreamHandler, &list);
	if (list == NULL) {
		IMP_LOG_ERR(TAG, "Channel Num:%d pop freeStreamHandler failed\n", decChn);
		goto err_pop_freeStreamHandler;
	}
	streamHandler = container_of(list, StreamHandler, list);
	streamHandler->decStream.decoderNal.i_payload = stream->decoderNal.i_payload;
	streamHandler->decStream.decoderNal.timeStamp = stream->decoderNal.timeStamp;
	memcpy(streamHandler->decStream.decoderNal.p_payload, stream->decoderNal.p_payload, stream->decoderNal.i_payload);
	ppic_out = &streamHandler->decElem.ijpegelem.pic_out;
	pnal_in = &streamHandler->decElem.ijpegelem.nal_in;
	framesize = C_ALIGN(dec_chn->attr.decAttr.maxWidth, 16) * C_ALIGN(dec_chn->attr.decAttr.maxHeight, 16) * 3 / 2;
	ppic_out->virAddr = streamHandler->frameInfo.virAddr;
	ppic_out->size = framesize;
	pnal_in->i_payload = streamHandler->decStream.decoderNal.i_payload;
	pnal_in->p_payload = streamHandler->decStream.decoderNal.p_payload;
	push_handler(dec_chn, &dec_chn->container.busyStreamHandler, list);
	sem_post(&dec_chn->container.busyHandlerSem);

	return 0;

err_pop_freeStreamHandler:
err_video_sem_timedwait_freeHandlerSem:
err_inv_decChn:
err_channel_num:
	return -1;
}

int IMP_Decoder_PollingFrame(int decChn, uint32_t timeoutMsec)
{
	DecChannel *dec_chn = NULL;
	struct timespec timeSpec = {
		.tv_sec = timeoutMsec / 1000,
		.tv_nsec = (timeoutMsec % 1000) * 1000000,
	};

	if ((decChn < 0) || (decChn >= NR_MAX_DEC_CHN)) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", decChn);
		goto err_channel_num;
	}

	dec_chn = &g_DecChannel[decChn];
	if (dec_chn->index < 0) {
		IMP_LOG_ERR(TAG, "the Decoder Channel id=%d hasn't been created\n", decChn);
		goto err_inv_decChn;
	}

	if (video_sem_timedwait(&dec_chn->container.doneHandlerSem, &timeSpec) < 0) {
		IMP_LOG_ERR(TAG, "channel num=%d, video_sem_timedwait timeout\n", decChn);
		goto err_video_sem_timedwait_doneHandlerSem;
	}

	return 0;

err_video_sem_timedwait_doneHandlerSem:
err_inv_decChn:
err_channel_num:
	return -1;
}

int IMP_Decoder_GetFrame(int decChn, IMPFrameInfo **frame)
{
	DecChannel *dec_chn = NULL;
	imp_video_list_t *list = NULL;
	StreamHandler *streamHandler = NULL;

	if ((decChn < 0) || (decChn >= NR_MAX_DEC_CHN)) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", decChn);
		goto err_channel_num;
	}

	dec_chn = &g_DecChannel[decChn];
	if (dec_chn->index < 0) {
		IMP_LOG_ERR(TAG, "the Decoder Channel id=%d hasn't been created\n", decChn);
		goto err_inv_decChn;
	}

	pop_handler(dec_chn, &dec_chn->container.doneStreamHandler, &list);
	if (list == NULL) {
		IMP_LOG_ERR(TAG, "the Decoder Channel id=%d hasn't been created\n", decChn);
		goto err_pop_handler_doneStreamHandler;
	}

	streamHandler = container_of(list, StreamHandler, list);
	streamHandler->frameInfo.width = streamHandler->decElem.ijpegelem.pic_out.img.i_stride[0];
	streamHandler->frameInfo.height = streamHandler->decElem.ijpegelem.pic_out.img.i_lines[0];
	streamHandler->frameInfo.timeStamp = streamHandler->decStream.decoderNal.timeStamp;
	*frame = &streamHandler->frameInfo;

	return 0;

err_pop_handler_doneStreamHandler:
err_inv_decChn:
err_channel_num:
	return -1;
}

int IMP_Decoder_ReleaseFrame(int decChn, IMPFrameInfo *frame)
{
	DecChannel *dec_chn = NULL;
	StreamHandler *streamHandler = NULL;

	if ((decChn < 0) || (decChn >= NR_MAX_DEC_CHN)) {
		IMP_LOG_ERR(TAG, "Invalid Channel Num: %d\n", decChn);
		goto err_channel_num;
	}

	dec_chn = &g_DecChannel[decChn];
	if (dec_chn->index < 0) {
		IMP_LOG_ERR(TAG, "the Decoder Channel id=%d hasn't been created\n", decChn);
		goto err_inv_decChn;
	}

	streamHandler = container_of(frame, StreamHandler, frameInfo);
	push_handler(dec_chn, &dec_chn->container.freeStreamHandler, &streamHandler->list);
	sem_post(&dec_chn->container.freeHandlerSem);

	return 0;

err_inv_decChn:
err_channel_num:
	return -1;
}
